﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Text;
using JESAI.Core.Extensions;

namespace JESAI.Logs.MLog
{
    /// <summary>
    /// 日志记录器工厂
    /// </summary>
    public class LoggerFactory
    {
        private static ConcurrentDictionary<string, ILogger> _loggerCache = new ConcurrentDictionary<string, ILogger>();

        /// <summary>
        /// 根据类别创建日志记录器
        /// </summary>
        /// <typeparam name="T">以此泛型全称作为类别名</typeparam>
        /// <returns></returns>
        public static ILogger<T> CreateLogger<T>()
        {
#pragma warning disable CS8603 // 可能返回 null 引用。
            return _loggerCache.GetOrAdd(typeof(T).FullName, (key) => new InternalLogger<T>(typeof(T).GetClassFullName())) as ILogger<T>;
#pragma warning restore CS8603 // 可能返回 null 引用。
        }

        /// <summary>
        /// 根据类别创建日志记录器
        /// </summary>
        /// <param name="categoryName">类别名</param>
        /// <returns></returns>
        public static ILogger CreateLogger(string categoryName)
        {
            return _loggerCache.GetOrAdd(categoryName, (key) => new InternalLogger<object>(categoryName));
        }

        /// <summary>
        /// 自定义的日志输出的动作,可以使用 <seealso cref="LoggerFactory.SetLogger(Action{LogContext}, bool)"/> 来赋值 <br/>
        /// 比如：通过自定义设置可以将日志输出到 asp.net core 的日志框架
        /// </summary>
        public static Action<LogContext> LogAction { internal set; get; }
        /// <summary>
        /// 是否仍然将日志输出到本地目录 <seealso cref="LoggerFactory.SetLogger(Action{LogContext}, bool)"/> 的第二个参数值
        /// </summary>
        public static bool EnableDefaultOutPut { internal set; get; }

        /// <summary>
        /// 设置的日志输出
        /// </summary>
        /// <param name="logAction"></param>
        /// <param name="enableDefaultOutPut"></param>
        public static void SetLogger(Action<LogContext> logAction, bool enableDefaultOutPut)
        {
            LogAction = logAction;
            EnableDefaultOutPut = enableDefaultOutPut;
        }

        /// <summary>
        /// 日志默认输出的基目录, 默认: <code>Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ".logs")</code>
        /// </summary>
        public static string BaseDir { internal set; get; } = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ".logs");
        /// <summary>
        /// 设置日志的默认输出目录
        /// </summary>
        /// <param name="path"></param>
        public static void SetBaseDirectory(string path)
        {
            path = path.TrimEnd('/', '\\');
            if (!Directory.Exists(path)) Directory.CreateDirectory(path);
            BaseDir = path;
        }

        /// <summary>
        /// 自定义获取日志输出目录的逻辑
        /// </summary>
        public static Func<SetOutFileArg, string[]> GetOutFileFunc { internal set; get; }
        /// <summary>
        /// 设置自定义计算日志输出路径的逻辑
        /// </summary>
        /// <param name="func"></param>
        public static void SetOutFile(Func<SetOutFileArg, string[]> func)
        {
            GetOutFileFunc = func;
        }

        /// <summary>
        /// 自定义日志输出格式的逻辑
        /// </summary>
        public static Func<SetOutFormatArg, string> GetOutFormatFunc { internal set; get; }

        /// <summary>
        /// 设置输出的日志格式,比如: 可以将日志内容格式化为json
        /// </summary>
        /// <param name="func"></param>
        public static void SetOutFormat(Func<SetOutFormatArg, string> func)
        {
            GetOutFormatFunc = func;
        }

        /// <summary>
        /// 设置自定义是否输出日志的判别逻辑
        /// </summary>
        public static Func<LogContext, bool> GetCanOutFunc { internal set; get; }
        /// <summary>
        /// 设置判别哪些日志能输出,比如: 设置 information 级别以下的日志不输出
        /// </summary>
        /// <param name="func"></param>
        public static void SetCanOut(Func<LogContext, bool> func)
        {
            GetCanOutFunc = func;
        }

        /// <summary>
        /// SetOutDirectory 方法参数
        /// </summary>
        public class SetOutFileArg
        {
            /// <summary>
            /// 日志信息(类别、级别、内容)
            /// </summary>
            public LogContext LogContext { internal set; get; }
            /// <summary>
            /// 当前使用的日志输出目录
            /// </summary>
            public string BaseDir { internal set; get; }
            /// <summary>
            /// 当前系统计算的日志输出文件路径
            /// </summary>
            public string PreLogFile { internal set; get; }
            /// <summary>
            /// 当前系统计算的日志输出文件路径(error、critical级别会额外计算一个路径,方便统计错误日志)
            /// </summary>
            public string PreErrorLogFile { internal set; get; }
        }

        /// <summary>
        /// SetOutFormat 方法参数
        /// </summary>
        public class SetOutFormatArg
        {
            /// <summary>
            /// 日志信息(类别、级别、内容)
            /// </summary>
            public LogContext LogContext { internal set; get; }
            /// <summary>
            /// 当前系统计算的日志输出
            /// </summary>
            public string PreMessage { internal set; get; }
        }
    }
}
